{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "cb354baf",
      "metadata": {
        "id": "cb354baf"
      },
      "source": [
        "[![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/langchain-ai/langchain-academy/blob/main/module-1/router.ipynb) [![Open in LangChain Academy](https://cdn.prod.website-files.com/65b8cd72835ceeacd4449a53/66e9eba12c7b7688aa3dbb5e_LCA-badge-green.svg)](https://academy.langchain.com/courses/take/intro-to-langgraph/lessons/58239412-lesson-5-router)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ce6fff79-25b5-4884-8aaa-e3ebb7ddd549",
      "metadata": {
        "id": "ce6fff79-25b5-4884-8aaa-e3ebb7ddd549"
      },
      "source": [
        "# Router\n",
        "\n",
        "## Review\n",
        "\n",
        "We built a graph that uses `messages` as state and a chat model with bound tools.\n",
        "\n",
        "We saw that the graph can:\n",
        "\n",
        "* Return a tool call\n",
        "* Return a natural language response\n",
        "\n",
        "## Goals\n",
        "\n",
        "We can think of this as a router, where the chat model routes between a direct response or a tool call based upon the user input.\n",
        "\n",
        "This is an simple example of an agent, where the LLM is directing the control flow either by calling a tool or just responding directly.\n",
        "\n",
        "![Screenshot 2024-08-21 at 9.24.09 AM.png](https://cdn.prod.website-files.com/65b8cd72835ceeacd4449a53/66dbac6543c3d4df239a4ed1_router1.png)\n",
        "\n",
        "Let's extend our graph to work with either output!\n",
        "\n",
        "For this, we can use two ideas:\n",
        "\n",
        "(1) Add a node that will call our tool.\n",
        "\n",
        "(2) Add a conditional edge that will look at the chat model model output, and route to our tool calling node or simply end if no tool call is performed.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "ebb4fc6e-7c85-4fc8-a4a9-0c7a527c4e5b",
      "metadata": {
        "id": "ebb4fc6e-7c85-4fc8-a4a9-0c7a527c4e5b"
      },
      "outputs": [],
      "source": [
        "%%capture --no-stderr\n",
        "%pip install --quiet -U langchain_google_genai langchain_core langgraph"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "885e92d9",
      "metadata": {
        "id": "885e92d9"
      },
      "outputs": [],
      "source": [
        "from google.colab import userdata\n",
        "GEMINI_API_KEY = userdata.get('GEMINI_API_KEY')"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9c564a67",
      "metadata": {
        "id": "9c564a67"
      },
      "source": [
        "**Note:** Obtain the necessary json key from the Google Cloud Console by following the instructions outlined in step 21_langchain_ecosystem/langchain/-01_gemini_standalone/Gemini_API_python.ipynb file. Once acquired, load the json key in Google Colab to proceed with the project."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "e3ba4df4-3045-49b1-9299-ced1fce14d24",
      "metadata": {
        "id": "e3ba4df4-3045-49b1-9299-ced1fce14d24"
      },
      "outputs": [],
      "source": [
        "from langchain_google_genai import ChatGoogleGenerativeAI\n",
        "\n",
        "def multiply(a: int, b: int) -> int:\n",
        "    \"\"\"Multiply a and b.\n",
        "\n",
        "    Args:\n",
        "        a: first int\n",
        "        b: second int\n",
        "    \"\"\"\n",
        "    return a * b\n",
        "\n",
        "llm = ChatGoogleGenerativeAI(model=\"gemini-1.5-flash\", api_key=GEMINI_API_KEY)\n",
        "llm_with_tools = llm.bind_tools([multiply])"
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## AI agent architectures\n",
        "\n",
        "\n",
        "The introduction of `ToolNode` and `tool_condition` in LangGraph represents a significant advancement in AI agent architectures. These components enhance the framework's flexibility and capability in several ways:\n",
        "\n",
        "**1. Simplified Tool Integration**\n",
        "\n",
        "With `ToolNode`, developers can seamlessly incorporate a variety of tools into their AI agents by passing a list of tools during initialization. This streamlined process reduces complexity and accelerates development.\n",
        "\n",
        "**2. Conditional Execution with `tool_condition`**\n",
        "\n",
        "The `tool_condition` feature allows for dynamic decision-making within the agent's workflow. Agents can evaluate conditions at runtime and choose appropriate actions, enabling more responsive and intelligent behavior.\n",
        "\n",
        "**3. Enhanced Support for Diverse Architectures**\n",
        "\n",
        "These features facilitate the implementation of various AI agent architectures, including:\n",
        "\n",
        "- **ReAct Architecture**: Integrates reasoning and action by allowing agents to decide when to invoke tools based on current context.\n",
        "- **DEPS (Describe, Explain, Plan, Select)**: Supports structured decision-making processes by enabling conditional tool usage.\n",
        "- **Reflexion Architecture**: Allows agents to reflect on actions and outcomes, adjusting behavior dynamically.\n",
        "- **Talker-Reasoner Architecture**: Separates communication and reasoning processes, with conditional tool invocation enhancing reasoning capabilities.\n",
        "- **Cognitive Architectures (e.g., Soar)**: Supports complex, human-like reasoning and decision-making processes through dynamic tool integration.\n",
        "\n",
        "By providing these capabilities, LangGraph's `ToolNode` and `tool_condition` contribute to the evolution of agentic AI, moving beyond static models to more adaptive and intelligent systems. This progression aligns with the broader trend of enhancing AI agents' reasoning and decision-making abilities, marking a pivotal step in the development of advanced AI architectures.\n\n",
        "**AI Agent architecture**:\n",
        "https://chatgpt.com/share/67362fc6-aed8-8004-9bcd-40a1f92b184e"
      ],
      "metadata": {
        "id": "H1YxmXnZtU9W"
      },
      "id": "H1YxmXnZtU9W"
    },
    {
      "cell_type": "markdown",
      "id": "ECazzuXBOEvt",
      "metadata": {
        "id": "ECazzuXBOEvt"
      },
      "source": [
        "**Note:** Warning indicates that the title key is being generated internally, likely within LangGraph or the Gemini integration when the tool is being bound, rather than being passed explicitly. So ignore the warning.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c77555a2",
      "metadata": {
        "id": "c77555a2"
      },
      "source": [
        " We use the [built-in `ToolNode`](https://langchain-ai.github.io/langgraph/reference/prebuilt/?h=tools+condition#toolnode) and simply pass a list of our tools to initialize it.\n",
        "\n",
        " We use the [built-in `tools_condition`](https://langchain-ai.github.io/langgraph/reference/prebuilt/?h=tools+condition#tools_condition) as our conditional edge."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "9a6fde4e-cceb-4426-b770-97ee4b41e9da",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 350
        },
        "id": "9a6fde4e-cceb-4426-b770-97ee4b41e9da",
        "outputId": "25225026-c45d-4d36-d6f6-169e8e22a931"
      },
      "outputs": [
        {
          "output_type": "display_data",
          "data": {
            "image/png": "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\n",
            "text/plain": [
              "<IPython.core.display.Image object>"
            ]
          },
          "metadata": {}
        }
      ],
      "source": [
        "from IPython.display import Image, display\n",
        "from langgraph.graph import StateGraph, START, END\n",
        "from langgraph.graph import MessagesState\n",
        "from langgraph.prebuilt import ToolNode\n",
        "from langgraph.prebuilt import tools_condition\n",
        "from langgraph.graph.state import CompiledStateGraph\n",
        "\n",
        "# Node\n",
        "def tool_calling_llm(state: MessagesState) -> MessagesState:\n",
        "    return {\"messages\": [llm_with_tools.invoke(state[\"messages\"])]}\n",
        "\n",
        "# Build graph\n",
        "builder: StateGraph = StateGraph(MessagesState)\n",
        "builder.add_node(\"tool_calling_llm\", tool_calling_llm)\n",
        "builder.add_node(\"tools\", ToolNode([multiply]))\n",
        "builder.add_edge(START, \"tool_calling_llm\")\n",
        "builder.add_conditional_edges(\n",
        "    \"tool_calling_llm\",\n",
        "    # If the latest message (result) from assistant is a tool call -> tools_condition routes to tools\n",
        "    # If the latest message (result) from assistant is a not a tool call -> tools_condition routes to END\n",
        "    tools_condition,\n",
        ")\n",
        "builder.add_edge(\"tools\", END)\n",
        "graph: CompiledStateGraph = builder.compile()\n",
        "\n",
        "# View\n",
        "display(Image(graph.get_graph().draw_mermaid_png()))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "id": "11b608c5-0c15-4fb7-aa24-80ce5774fb85",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "11b608c5-0c15-4fb7-aa24-80ce5774fb85",
        "outputId": "b5e20f0b-ab74-46d3-98f2-bbe23e1505b4"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "================================\u001b[1m Human Message \u001b[0m=================================\n",
            "\n",
            "What is a product of 2 and 3\n",
            "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
            "Tool Calls:\n",
            "  multiply (c6579ad3-dfbb-4686-9639-c3338c9c9cf2)\n",
            " Call ID: c6579ad3-dfbb-4686-9639-c3338c9c9cf2\n",
            "  Args:\n",
            "    a: 2.0\n",
            "    b: 3.0\n",
            "=================================\u001b[1m Tool Message \u001b[0m=================================\n",
            "Name: multiply\n",
            "\n",
            "6\n"
          ]
        }
      ],
      "source": [
        "from langchain_core.messages import HumanMessage, SystemMessage\n",
        "messages = [SystemMessage(content=\"\") , HumanMessage(content=\"What is a product of 2 and 3\")]\n",
        "messages = graph.invoke({\"messages\": messages})\n",
        "for m in messages['messages']:\n",
        "    m.pretty_print()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "KZsCLCr1NVEC",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "KZsCLCr1NVEC",
        "outputId": "3bbcc4d7-ad3b-42f6-fe29-cb6e84645034"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "================================\u001b[1m Human Message \u001b[0m=================================\n",
            "\n",
            "Multiply 6 and 5.\n",
            "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
            "Tool Calls:\n",
            "  multiply (d61e705f-e2e9-4d0f-8497-2a40f075187b)\n",
            " Call ID: d61e705f-e2e9-4d0f-8497-2a40f075187b\n",
            "  Args:\n",
            "    a: 6.0\n",
            "    b: 5.0\n",
            "=================================\u001b[1m Tool Message \u001b[0m=================================\n",
            "Name: multiply\n",
            "\n",
            "30\n"
          ]
        }
      ],
      "source": [
        "from langchain_core.messages import HumanMessage\n",
        "messages = [HumanMessage(content=\"Multiply 6 and 5.\")]\n",
        "messages = graph.invoke({\"messages\": messages})\n",
        "for m in messages['messages']:\n",
        "    m.pretty_print()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "34708377-16b6-4474-9e23-71890c1fb36e",
      "metadata": {
        "id": "34708377-16b6-4474-9e23-71890c1fb36e"
      },
      "source": [
        "Now, we can see that the graph runs the tool!\n",
        "\n",
        "It responds with a `ToolMessage`.\n",
        "\n",
        "## LangGraph Studio\n",
        "\n",
        "--\n",
        "\n",
        "**⚠️ DISCLAIMER**\n",
        "\n",
        "*Running Studio currently requires a Mac. If you are not using a Mac, then skip this step.*\n",
        "\n",
        "--\n",
        "\n",
        "Load the `router` in Studio, which uses `module-1/studio/router.py` set in `module-1/studio/langgraph.json`."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "43782c33-0f41-47f2-ae38-ddb2cd4ba6f8",
      "metadata": {
        "id": "43782c33-0f41-47f2-ae38-ddb2cd4ba6f8"
      },
      "outputs": [],
      "source": []
    }
  ],
  "metadata": {
    "colab": {
      "provenance": []
    },
    "kernelspec": {
      "display_name": "Python 3 (ipykernel)",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.12.6"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}
